/*
 * @Author: Du Weixing duweixing@sgsimulation.com
 * @Date: 2024-09-09 18:46:53
 * @LastEditors: Du Weixing duweixing@sgsimulation.com
 * @LastEditTime: 2024-12-06 22:28:57
 * @FilePath: \SGFEM\Solver\SectionCalculator\BeamSection\SectionParser\src\BeamSectionParser.cpp
 * @Description: 
 * 
 * Copyright (c) 2024 by 神工仿真, All Rights Reserved. 
 */
#include "BeamSectionParser.h"
#include <assert.h>
#include <algorithm>
#include <iostream>
#include "DBManager/IService/Input/Material/IIsotropicMaterialService.h"
#include "DBManager/IService/Input/Material/IMaterialSummaryService.h"
#include "DBManager/IService/Input/Property/IPBEAMLService.h"
#include "DBManager/IService/Input/Property/IPBEAMService.h"
#include "DBManager/IService/Input/Property/IPropertySummaryService.h"
#include "../Common/BeamSecPropCalculatorInfo.h"
#include "../FormulaMethod/Interface/BeamSectionFormulaCalculatorFactory.h"

using SG::DataStructure::Common::Status;
using SG::DataStructure::Common::Id;
using SG::DataStructure::FEM::IsotropicMaterial;
using SG::DataStructure::FEM::PropertyTypes;
using SG::DataStructure::FEM::BeamSectionStandardTypes;
using SG::DataStructure::FEM::PBEAMLData;
using SG::DataStructure::FEM::PBEAMData;
using SG::FEMSolver::Element::BeamSectionParser;
using namespace SG::DBManager;

/** @brief 通过 id 获得梁属性
 *
 * 当首次遇到某种类型的截面，会计算梁的属性
 */
void BeamSectionParser::GetSectionProperty (const DBServiceFactorySP dbServiceFactory, Id pId, _OUT PBEAMData& property)
{
    // 属性号为 `pId` 的截面并非第一次处理，直接从缓存中提取属性
    auto it = m_property.find (pId);
    if (it != m_property.end ())
    {
        property = it->second;
        return;
    }

    // 属性号为 `pId` 的截面首次处理
    // 按照类型(直接指定值，标准形状，任意截面)分别调用相应的计算功能
    PropertyTypes type = dbServiceFactory->get<IPropertySummaryService> ()->GetPropertyType (pId);

    switch (type)
    {
    case PropertyTypes::PROTYPE_PBEAM: {
        // 使用梁属性数值定义的截面，直接获取截面属性
        dbServiceFactory->get<IPBEAMService> ()->FindById (pId, property);
        break;
    }
    case PropertyTypes::PROTYPE_PBEAML: {
        // 标准定义形状截面，使用对应计算工具定义
        PBEAMLData pBeamL;
        dbServiceFactory->get<IPBEAMLService> ()->FindById (pId, pBeamL);
        BeamSectionStandardTypes type = pBeamL.GetBeamSectionStandardTypes ();

        auto calculator = SG::FEMSolver::Element::BeamSectionFormulaCalculatorFactory::Create (type);
        property        = calculator->Compute (pBeamL);
        break;
    }
    // 自定义形状截面（未来增加case分支）
    default:
        // 未找到属性定义，处理不了
        std::cout << NOT_FIND_BEAM_SECTION_DEFINITION;
        assert (0);
        break;
    }

    // 缓存数据，避免再次查询数据库系统
    m_property[pId] = property;

    // 查询材料数据，并缓存到
    auto materialType = dbServiceFactory->get<IMaterialSummaryService> ()->GetMaterialType (property.m_mId);
    // 仅仅支持线弹性材料
    assert (std::find(materialType.begin(),materialType.end(), SG::DataStructure::FEM::MaterialTypes::MATTYPE_Isotropic ) != materialType.end());
    IsotropicMaterial material;
    if (Status::STATUS_Failure == dbServiceFactory->get<IIsotropicMaterialService> ()->FindById (property.m_mId, material))
    {
        // 未在数据库中找到材料定义
        assert (0);
    }
    // 不同`属性号pId`的截面具有相同`材料mId`时，后一次的材料属性会对前一次材料属性覆盖。此时不影响计算
    m_mat[property.m_mId] = material;
}

void BeamSectionParser::GetMatrial (Id mId, IsotropicMaterial& material) const
{
    auto it = m_mat.find (mId);
    if (it == m_mat.end ())
    {
        // 发生异常的可能情况为：
        // 1. 材料属性号数据出错；
        // 2. 调用本函数前，没有正确调用 GetSectionProperty ()
        assert (0);
        return;
    }

    material = it->second;
}